package it.eng.area118.mdogpscollector.service;

import it.eng.area118.mdogpscollector.db.Item;
import it.eng.area118.mdogpscollector.model.CheckPoint;
import it.eng.area118.mdogpscollector.model.PerstRootBean;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

import org.garret.perst.Index;
import org.garret.perst.Key;
import org.garret.perst.Storage;

public class IndexLookupService implements LookupService {

	protected Index index;
	protected Class entityClass;
	protected Storage storage;

	public IndexLookupService(Index index, Class entityClass, Storage storage) {
		super();
		this.index = index;
		this.entityClass = entityClass;
		this.storage = storage;
	}

	public <E extends Item> List lookup(String pattern, Comparator<E> comp) {
		return lookup(pattern, false, comp);
	}

	public <E extends Item> List lookup(String pattern, boolean checkNext, Comparator<E> comp) {
		Key from = new Key(pattern, true);
		Key to = null;
		if (checkNext) {
			to = new Key(getNextString(pattern), true);
		} else {
			to = new Key(pattern, true);
		}
		Iterator iterator = index.iterator(from, to, Index.ASCENT_ORDER);
		// uso un sorted set in modo da avere una lista ordinatea e con oggetti
		// unici
		if (comp == null) {
			comp = new Comparator() {
				public int compare(Object o1, Object o2) {
					Item i1 = (Item) o1;
					Item i2 = (Item) o2;
					return i1.getItemKey().compareTo(i2.getItemKey());
				}
			};
		}
		SortedSet list = new TreeSet(comp);
		while (iterator.hasNext()) {
			Item toBeFiltered = (Item) iterator.next();
			list.add(toBeFiltered);
		}
		return new ArrayList(list);
	}

	@Override
	public <E extends Item> List getAll(Comparator<E> comp) {
		Iterator iterator = index.iterator();
		if (comp == null) {
			comp = new Comparator() {
				public int compare(Object o1, Object o2) {
					Item i1 = (Item) o1;
					Item i2 = (Item) o2;
					return i1.getItemKey().compareTo(i2.getItemKey());
				}
			};
		}

		SortedSet list = new TreeSet(comp);
		while (iterator.hasNext()) {
			Item toBeFiltered = (Item) iterator.next();
			list.add(toBeFiltered);
		}
		return new ArrayList(list);
	}

	public LookupViewer getViewer() {
		return new LookupViewer() {
			public String show(Object item) {
				if (item != null) {
					return ((Item) item).getName();
				}
				return "";
			}
		};
	}

	/**
	 * Genera una stringa lessicalmente successiva a quella data
	 * 
	 * @param s
	 * @return
	 */
	private String getNextString(String s) {
		char[] chars = s.toUpperCase().toCharArray();
		int overflow = 1;
		for (int i = chars.length - 1; i > 0; i--) {
			if (overflow == 1) {
				if (chars[i] == 'Z') {
					chars[i] = 'A';
					overflow = 1;
				} else {
					chars[i] = (char) (chars[i] + overflow);
					overflow = 0;
				}
			}
		}
		String newString = new String(chars);
		return newString;
	}

	@Override
	public <E extends Item> E getItem(String key) {
		@SuppressWarnings("unchecked")
		List list = lookup(key, null);
		if (list == null) {
			return null;
		}
		if (list.size() == 0) {
			return null;
		}
		if (list.size() > 1) {
			throw new IllegalStateException("More than one object found!!! Check the key!!!!");
		}
		E e = (E) list.get(0);
		return e;

	}

	public Storage getStorage() {
		return storage;
	}

	public void reset(Class entityClass, Storage storage) {
		this.storage = storage;
		PerstRootBean root = (PerstRootBean) storage.getRoot();
		Index i = root.getIndex(CheckPoint.class, storage, false);
		this.index = i;
		this.entityClass = entityClass;
		this.storage = storage;

	}
}
